﻿using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Linq;
using PD.ShP.Code;
using PD.ShP.Code.DataModel;

namespace PD.ShP.Workflows
{
    /// <summary>
    /// The context of the PD application.
    /// </summary>
    [Serializable]
    public class InvoiceProcessingController
    {
        /// <summary>
        /// The context of currently run workflow.
        /// </summary>
        private IWorkflowContext workflowContext;

        /// <summary>
        /// Initializes a new instance of the <see cref="InvoiceProcessingController"/> class.
        /// </summary>
        /// <param name="workflowContext">The context of currently run workflow.</param>
        public InvoiceProcessingController(IWorkflowContext workflowContext)
        {
            if (workflowContext == null)
            {
                throw new ArgumentNullException("workflowContext");
            }

            this.workflowContext = workflowContext;
        }

        /// <summary>
        /// Gets a value indicating whether the invoice info is correct.
        /// </summary>
        /// <value>
        /// <c>true</c> if the invoice info is correct; otherwise, <c>false</c>.
        /// </value>
        public bool InvoiceIsCorrect
        {
            get
            {
                SPListItem invoice = this.workflowContext.WorkflowProperties.Item;
                var statusValue = invoice[Fields.Status];
                if (statusValue == null)
                {
                    SPList invoicesList = this.workflowContext.WorkflowProperties.List;
                    statusValue = invoicesList.Fields[Fields.Status].DefaultValue;
                }

                return string.Equals(statusValue.ToString(), GetStringValue(Status.Correct, typeof(ChoiceAttribute)), StringComparison.OrdinalIgnoreCase);
            }
        }

        /// <summary>
        /// Gets the involved supervisor identity.
        /// </summary>
        public string InvolvedSupervisorIdentity
        {
            get { return this.GetInvoiceIdentity(Fields.InvolvedSupervisor.Guid); }
        }

        /// <summary>
        /// Gets the involved accountant identity.
        /// </summary>
        public string InvolvedAccountantIdentity
        {
            get { return this.GetInvoiceIdentity(Fields.InvolvedAccountant.Guid); }
        }

        /// <summary>
        /// Gets the chief accountant identity.
        /// </summary>
        public string ChiefAccountantIdentity
        {
            get
            {
                using (SiteDataContext context = new SiteDataContext(this.workflowContext.WorkflowProperties.Web.Url))
                {
                    ConfigItem config = context.Config.FirstOrDefault();
                    if (config != null && config.ChiefAccountantId.HasValue)
                    {
                        SPUser user = this.workflowContext.WorkflowProperties.Web.SiteUsers.GetByIdSafe(config.ChiefAccountantId.Value);
                        return user != null ? user.LoginName : null;
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// Gets the CEO identity.
        /// </summary>
        public string CEOIdentity
        {
            get
            {
                using (SiteDataContext context = new SiteDataContext(this.workflowContext.WorkflowProperties.Web.Url))
                {
                    ConfigItem config = context.Config.FirstOrDefault();
                    if (config != null && config.CEOId.HasValue)
                    {
                        SPUser user = this.workflowContext.WorkflowProperties.Web.SiteUsers.GetByIdSafe(config.CEOId.Value);
                        return user != null ? user.LoginName : null;
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// Gets the invoice total amount.
        /// </summary>
        public double InvoiceTotalAmount
        {
            get
            {
                SPListItem invoice = this.workflowContext.WorkflowProperties.Item;
                return (invoice[Fields.TotalAmount] as double?).GetValueOrDefault();
            }
        }

        /// <summary>
        /// Gets a value indicating whether the invoice's amount is less than first threshold.
        /// </summary>
        /// <value>
        /// <c>true</c> if the invoice's amount is less than first threshold; otherwise, <c>false</c>.
        /// </value>
        public bool AmountIsLessThanFirstThreshold
        {
            get
            {
                using (SiteDataContext context = new SiteDataContext(this.workflowContext.WorkflowProperties.Web.Url))
                {
                    return this.InvoiceTotalAmount < context.Config.FirstOrDefault().FirstAcceptanceThreshold.GetValueOrDefault((double)10000);
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether the invoice's amount is greater than second threshold.
        /// </summary>
        /// <value>
        /// <c>true</c> if the invoice's amount is greater than second threshold; otherwise, <c>false</c>.
        /// </value>
        public bool AmountIsGreaterThanSecondThreshold
        {
            get
            {
                using (SiteDataContext context = new SiteDataContext(this.workflowContext.WorkflowProperties.Web.Url))
                {
                    return this.InvoiceTotalAmount > context.Config.FirstOrDefault().SecondAcceptanceThreshold.GetValueOrDefault((double)50000);
                }
            }
        }

        /// <summary>
        /// Sets the invoice status.
        /// </summary>
        /// <param name="status">The status should be set.</param>
        internal void SetInvoiceStatus(Status status)
        {
            SPListItem invoice = this.workflowContext.WorkflowProperties.Item;
            invoice[Fields.Status] = status;
            invoice.SystemUpdate(false);
        }

        /// <summary>
        /// Gets the string value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="attributeType">Type of the attribute.</param>
        /// <returns>
        /// Attribute string value of enum if assigned; null otherwise.
        /// </returns>
        private static string GetStringValue(Enum value, Type attributeType)
        {
            var type = value.GetType();
            var fieldInfo = type.GetField(value.ToString());
            var attributes = fieldInfo.GetCustomAttributes(attributeType, false) as ChoiceAttribute[];
            return attributes.Length > 0 ? attributes[0].Value : null;
        }

        /// <summary>
        /// Gets the invoice identity.
        /// </summary>
        /// <param name="fieldId">The field id.</param>
        /// <returns>
        /// The user name of the user or null.
        /// </returns>
        private string GetInvoiceIdentity(Guid fieldId)
        {
            SPListItem invoice = this.workflowContext.WorkflowProperties.Item;
            string fieldValue = invoice[fieldId] as string;
            if (!string.IsNullOrEmpty(fieldValue))
            {
                SPFieldUserValue userValue = new SPFieldUserValue(this.workflowContext.WorkflowProperties.Web, fieldValue);
                return userValue.User != null ? userValue.User.LoginName : null;
            }

            return null;
        }
    }
}
